#include "dspSimulator/instruction/SUB.h"

namespace dspsimulator {
    void SUB::generate_ir(const std::shared_ptr<simulator::IRGenElement> &ir_gen_element) {
        std::shared_ptr<simulator::LLVMJit> llvm_jit = ir_gen_element->m_llvm_jit;
        RegIRCopy &reg_ir_copy = ir_gen_element->m_reg_ir_copy;
        std::shared_ptr<llvm::IRBuilder<>> ir_builder = llvm_jit->ir_builder();
        // SUB .func src1_reg,imm,dst_reg
        auto op1 = std::dynamic_pointer_cast<SingleReg>(m_op1);
        auto op2 = std::dynamic_pointer_cast<Immediate32>(m_op2);
        auto op3 = std::dynamic_pointer_cast<SingleReg>(m_op3);

        if (op1 && op2 && op3) {
            std::string src1_name = get_reg_name(op1->reg());
            llvm::Value *src1 = reg_ir_copy[src1_name];
            u32 src2 = op2->data();
            std::string dst_name = get_reg_name(op3->reg());
            llvm::Value *dst_ptr = IRGenerator::get_global_value_ptr(llvm_jit, dst_name);
            llvm::Value *result = ir_builder->CreateSub(src1, ir_builder->getInt32(src2));
            ir_builder->CreateStore(result, dst_ptr);
        }
    }

    std::shared_ptr<DspInstruction>
    SUB::decode_standard_instruction(const std::shared_ptr<DspInstructionInfo> &dsp_instruction_info) {
        std::shared_ptr<SUB> sub;
        return sub;
    }

    std::shared_ptr<DspInstruction>
    SUB::decode_compact_instruction(const std::shared_ptr<DspInstructionInfo> &dsp_instruction_info) {
        std::shared_ptr<SUB> sub;
        std::bitset<16> &data = dsp_instruction_info->m_compact_bits;
        if (common::check_bits<6>(data, 0b111011, 1) && common::check_bits<6>(data, 0b011110, 10)) {
            sub = std::make_shared<SUB>(dsp_instruction_info->address(), 2);
            u32 src2 = common::extract_bits<3>(data, 7).to_ulong();
            u32 dst = src2;
            bool s = data[0];
            sub->m_func_unit = s ? FuncUnit::D1 : FuncUnit::D2;
            sub->m_op1 = std::make_shared<SingleReg>(get_src2_reg32_kind(src2, s));
            sub->m_op2 = std::make_shared<Immediate32>(1);
            sub->m_op3 = std::make_shared<SingleReg>(get_dst_reg32_kind(dst, s));
            sub->m_p = dsp_instruction_info->p();
        }
        return sub;
    }

    std::string SUB::to_string() const {
        return get_standard_condition(m_creg_z) + m_name + " " + get_function_unit_name(m_func_unit) + " " +
               m_op1->to_string() + "," + m_op2->to_string() + "," + m_op3->to_string();
    }
}